package com.ruoyi.framework.intercepter;

import com.ruoyi.project.app.util.XException;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

@SuppressWarnings("ALL")
public class JwtInterceptor implements HandlerInterceptor, JwtHelperInterface {
    @Autowired
    private CacheManager cacheManager;
    // 是否单点登录
    private boolean single = true;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 如果请求是options请求是cors跨域请求，设置allow对应头信息
        if (!RequestMethod.OPTIONS.toString().equals(request.getMethod())) {

            // Cookie[] cookies = request.getCookies();
            // Get authorization from Http request
            final String authHeader = request.getHeader("authorization");

            // Check the authorization, check if the token is started by "Bearer "
            if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                throw new XException("Missing or invalid Authorization header");
            }

            // Then get the JWT token from authorization
            final String jwtToken = authHeader.substring(7);

            try {
                // Use JWT parser to check if the signature is valid with the Key "secretKey"

                // Add the claim to request header
                Claims claims = parseJwt(jwtToken);
                request.setAttribute("userId", claims.get("userId"));
                request.setAttribute("username", claims.get("username") != null ? claims.get("username") : "");

                if (single) {
                    // 从缓存当前取出当前的jwtToken对比，实现单点登录
                    Cache cache = cacheManager.getCache("system");
                    String jwtTokenCache = cache.get("app_token_" + claims.get("userId"), String.class);
                    if (!jwtToken.equals(jwtTokenCache)) {
                        throw new XException("Invalid token");
                    }
                }
            } catch (Exception e) {
                //throw new XException("Invalid token");
                resultError(response, 5, "登录无效");
                return false;
            }
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        //Cookie cookie = new Cookie("uid", "1");
        //response.addCookie();
    }

    private void resultError(HttpServletResponse response, int code, String msg) {
        //这句话的意思，是告诉servlet用UTF-8转码，而不是用默认的ISO8859
        response.setCharacterEncoding("UTF-8");
        //设置返回json字符串格式
        response.setContentType("application/json; charset=utf-8");
        //返回token失效的提示
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
            writer.write("{\"code\":" + code + ",\"msg\":\"" + msg + "\"}");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null) writer.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                if (writer != null) writer.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
